<template>
  <div>
    <!-- 编辑表单 -->
    <el-dialog :title="actionTitle" :visible.sync="isModal" size="50%">
      <el-form :inline="true" :model="editForm" :size="size">
        <el-form-item
          v-for="(field, index) in fields"
          :key="index"
          :label="field.name"
          :label-width="formLabelWidth"
        >
          <template v-if="field.type === 'select'">
            <el-select clearable v-model="editForm[field.field]">
              <template v-for="(codeType, index) in getCodeTypeMap(field)">
                <el-option :value="codeType.value" :key="index" :label="codeType.name"></el-option>
              </template>
            </el-select>
          </template>
          <template v-else-if="field.type === 'date'">
            <el-date-picker
              v-model="editForm[field.field]"
              type="datetime"
              value-format="yyyy-MM-dd HH:mm:ss"
              placeholder="选择日期时间"
            ></el-date-picker>
          </template>
          <template v-else>
            <el-input v-model="editForm[field.field]" :placeholder="field.name"></el-input>
          </template>
        </el-form-item>
      </el-form>

      <div slot="footer" class="dialog-footer">
        <el-button :size="size" :loading="false" type="primary" @click="postForm">确 定</el-button>
        <el-button :size="size" @click="isModal = false">取 消</el-button>
      </div>
    </el-dialog>

    <!-- 搜索表单 -->
    <search-form :size="size" :isSearch="isSearch" :fields="fields" :form="form" @search="search"
                 @reset="formReset"></search-form>

    <!-- 表格 -->
    <el-card shadow="never">
      <div>
        <!-- 工具栏 -->
        <div class="tool-bar" v-if="isToolbar">
          <template v-if="isDefaultBtn">
            <el-button-group>
              <el-button :size="size" icon="el-icon-plus" @click="saveHandle">新增</el-button>
              <el-button :size="size" icon="el-icon-edit" @click="updateHandle">修改</el-button>
              <el-button :size="size" icon="el-icon-delete" @click="deleteHandle">删除</el-button>
            </el-button-group>
          </template>

          <template v-for="(btn, index) in btns">
            <el-button :size="size" :key="index" @click="btnClick(btn)">{{btn.title}}</el-button>
          </template>

          <!-- 工具栏插槽 -->
          <slot name="toolbar"></slot>
        </div>

        <!--elementui 表格-->
        <!--<el-table
          :data="rows"
        >
          <el-table-column
            type="selection"
            width="55"/>
          <template v-for="field in fields">
              <template v-if="field.slot">
                <el-table-column :key="`slot:${field.field}`" :label="field.name">
                  <template slot-scope="scope">
                    <slot :name="field.slot" :row="scope.row"></slot>
                  </template>
                </el-table-column>
              </template>
              <template v-else>
                <el-table-column
                  :key="field.field"
                  :prop="field.field"
                  :label="field.name"/>
              </template>
            </template>
        </el-table>-->

        <!-- 本地表格 -->
        <div v-loading="!show" style="padding: 0px 8px;">
          <slot></slot>
          <table class="table">
            <thead>
            <tr>
              <th v-if="checkbox.show" style="text-align: center;">
                <el-checkbox v-model="checkbox.checked" @change="selectToggle"></el-checkbox>
              </th>

              <template v-for="(field, index) in fields">
                <th v-show="!field.hidden" :key="index" :width="field.width">{{field.name}}</th>
              </template>
            </tr>
            </thead>

            <tbody>
            <tr :key="index" v-for="(row, index) in rows" @dblclick="cellDbclick($event, row)">
              <td v-if="checkbox.show" style="text-align: center;">
                <el-checkbox v-model="row.checked" :key="index"></el-checkbox>
              </td>
              <template v-for="(field, fieldIndex) in fields">
                <td
                  v-if="!field.hidden"
                  :key="fieldIndex"
                  :width="field.width"
                >
                  <template v-if="isFieldSolt(field.field)">
                    <slot :name="field.field" :row="row"></slot>
                  </template>
                  <template v-else>
                    <template v-if="field.formatter != null">
                      <span v-html="field.formatter(cellFormatter(field, row), row)"></span>
                    </template>
                    <template v-else>
                      <span
                        :title="cellFormatter(field, row)"
                      >{{cellFormatter(field, row)}}</span>
                    </template>
                  </template>
                  <!--<span>
                    <template v-if="field.type === 'select'">
                      <el-select clearable v-model="row[field.field]">
                        <template v-for="(codeType, index) in getCodeTypeMap(field)">
                          <el-option :value="codeType.value" :key="index" :label="codeType.name"></el-option>
                        </template>
                      </el-select>
                    </template>
                    <template v-else-if="field.type === 'date'">
                      <el-date-picker
                        v-model="row[field.field]"
                        type="datetime"
                        value-format="yyyy-MM-dd HH:mm:ss"
                        placeholder="选择日期时间"
                      ></el-date-picker>
                    </template>
                    <template v-else>
                      <el-input v-model="row[field.field]" :placeholder="field.name"></el-input>
                    </template>
                  </span>-->
                </td>
              </template>
            </tr>
            <tr v-if="rows.length === 0">
              <td :colspan="noDataColspan" style="text-align: center;">没有数据</td>
            </tr>
            </tbody>
          </table>
        </div>

        <div class="pagination">
          <el-pagination
            @size-change="handleSizeChange"
            @current-change="getList"
            :current-page.sync="pageInfo.page"
            :page-sizes="[10, 20, 30, 40]"
            :page-size.sync="pageInfo.rows"
            layout="total, sizes, prev, pager, next, jumper"
            :total="this.total"
          ></el-pagination>
        </div>
      </div>
    </el-card>
  </div>
</template>

<script>
export default {

  name: 'base-table',

  props: {

    // 是否默认双击事件
    isDefaultDbclick: {
      type: Boolean,
      default: false
    },

    // 条件
    query: {
      type: Object,
      default: null
    },

    // 是否显示搜索条件
    isSearch: {
      type: Boolean,
      default: true
    },

    // 是否显示工具栏
    isToolbar: {
      type: Boolean,
      default: true
    },

    // 字段配置
    fields: {
      type: Array,
      default: () => []
    },

    // 模块基础地址
    baseURL: {
      type: String,
      default: ''
    },

    api: {
      type: Object,
      default: () => {
        return {
          'save': '/save',
          'delete': '/delete',
          'update': '/update',
          'query': '/queryPage'
        }
      }
    },

    // 按钮配置
    btns: {
      type: Array,
      default: () => {
        return []
      }
    },

    // 是否显示默认按钮
    isDefaultBtn: {
      type: Boolean,
      default: () => {
        return true
      }
    },

    // 尺寸
    size: {
      type: String,
      default: () => {
        return 'small'
      }
    }
  },

  data () {
    return {

      rows: [],
      pageInfo: {
        page: 1,
        rows: 10
      },
      total: 0,
      isModal: false,
      checkbox: {
        checked: false,
        show: true
      },
      action: 'save',
      editForm: null,
      form: null,
      show: false,
      loading: {
        canCancel: true,
        onCancel: () => {
          this.show = true
        },
        opacity: 0,
        color: 'rgb(0, 123, 255)'
      },

      // 删除操作确认框
      deleteAction: {
        isDialog: false,
        dialogMsg: '确认删除该行?',
        ok: () => {

        }
      },

      transform: '',
      formLabelWidth: '100px'
    }
  },

  computed: {
    maxPage () {
      if (this.total % this.pageInfo.rows === 0) {
        return parseInt(this.total / this.pageInfo.rows)
      }
      return parseInt(this.total / this.pageInfo.rows) + 1
    },

    actionTitle () {
      if (this.action === 'save') {
        return '新增表单'
      } else if (this.action === 'update') {
        return '编辑表单'
      }
      return '表单'
    },

    noDataColspan () {
      let colspan = 0
      for (let index = 0; index < this.fields.length; index++) {
        const field = this.fields[index]
        if (!field.hidden) {
          colspan++
        }
      }
      if (this.checkbox.show) {
        colspan++
      }
      return colspan
    }
  },

  methods: {

    // 取得代码类型列表
    getCodeTypeMap (field) {
      return this.$store.state.cache.codeInfo[field.codeType]
    },

    isFieldSolt (field) {
      return (typeof this.$scopedSlots[field]) !== 'undefined'
    },

    handleSizeChange (val) {
      this.pageInfo.rows = val
      this.getList()
    },

    getElementLeft (element) {
      var actualLeft = element.offsetLeft
      var current = element.offsetParent
      while (current !== null) {
        actualLeft += (current.offsetLeft + current.clientLeft)
        current = current.offsetParent
      }
      return actualLeft
    },

    getElementTop (element) {
      var actualTop = element.offsetTop
      var current = element.offsetParent
      while (current !== null) {
        actualTop += (current.offsetTop + current.clientTop)
        current = current.offsetParent
      }
      return actualTop
    },

    // 单元格双击事件
    cellDbclick (event, row) {
      row.editer = !row.editer
      if (!this.isDefaultDbclick) {
        return
      }

      this.initCheckbox(this.rows)
      row.checked = true
      this.updateHandle()
    },

    // 单元格格式化
    cellFormatter (field, row) {
      // 处理字符串
      let val = String(row[field.field])
      // 处理为空情况
      val = val === null || val === 'null' ? '' : val
      // 处理需要格式化内容
      if (typeof field.codeType !== 'undefined') {
        let codeTypeName = field.codeType
        let codeInfo = this.$store.state.cache.codeInfo[codeTypeName]
        // 处理为空情况
        if (typeof codeInfo === 'undefined') {
          return
        }
        for (let index = 0; index < codeInfo.length; index++) {
          const element = codeInfo[index]
          if (element.value === val) {
            return element.name
          }
        }
        return val
      } else {
        return val
      }
    },

    // 提交表单
    postForm () {
      const tmpParam = this.editForm
      delete tmpParam.checked
      if (this.action === 'save') {
        this
          .$post(this.baseURL + this.api.save, tmpParam)
          .then(data => {
            if (data.success) {
              this.$message({
                showClose: true,
                message: '保存成功',
                type: 'success'
              })
              this.isModal = false
              this.getList()
            } else {
              this.$message({
                showClose: true,
                message: data.msg,
                type: 'error'
              })
            }
          })
      } else if (this.action === 'update') {
        this
          .$post(this.baseURL + this.api.update, tmpParam)
          .then(data => {
            if (data.success) {
              this.isModal = false
              this.$message({
                showClose: true,
                message: '更新成功',
                type: 'success'
              })
              this.getList()
            } else {
              this.$message({
                showClose: true,
                message: data.msg,
                type: 'error'
              })
            }
          })
      }
    },

    // 表单重置
    formReset () {
      this.initSearchForm()
    },

    selectToggle () {
      for (let i = 0; i < this.rows.length; i++) {
        const row = this.rows[i]
        row.checked = this.checkbox.checked
      }
    },

    // 取被选中的行数据
    getSelectedRows () {
      const tmpList = []
      for (let i = 0; i < this.rows.length; i++) {
        const row = this.rows[i]
        if (row.checked) {
          tmpList.push(row)
        }
      }
      return tmpList
    },

    saveHandle () {
      this.initEditForm()
      this.isModal = true
      this.action = 'save'
    },

    deleteHandle () {
      const rows = this.getSelectedRows()
      if (rows.length !== 1) {
        this.$message({
          message: '请选中一行数据',
          showClose: true,
          type: 'warning'
        })
        return
      }

      this.$confirm('此操作将永久删除该数据, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        this.show = false
        const row = rows[0]
        delete row.checked
        this
          .$post(this.baseURL + this.api.delete, row)
          .then(data => {
            if (data.success) {
              this.$message({
                type: 'success',
                showClose: true,
                message: '删除成功!'
              })
              this.deleteAction.isDialog = false
              this.checkbox.checked = false
              this.show = true
              this.getList()
            } else {
              this.$message({
                type: 'info',
                message: '已取消删除'
              })
              this.getList()
            }
          })
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        })
      })
    },

    updateHandle () {
      const rows = this.getSelectedRows()
      if (rows.length !== 1) {
        this.$message({
          message: '请选中一行数据',
          showClose: true,
          type: 'warning'
        })
        return
      }
      /**
       * 对象拷贝,防止改动到表格内容
       */
      const tmpRow = JSON.parse(JSON.stringify(rows[0]))

      // 遍历对象转字符串
      for (let key in tmpRow) {
        tmpRow[key] = tmpRow[key] + ''
      }

      this.editForm = tmpRow
      this.isModal = true
      this.action = 'update'
    },

    // 初始化checkbox
    initCheckbox (rows) {
      for (let i = 0; i < rows.length; i++) {
        const row = rows[i]
        row.checked = false
      }
      return rows
    },

    // 查询
    search () {
      this.pageInfo.page = 1
      this.getList()
    },

    getList () {
      this.show = false
      const tmpParam = this.form
      tmpParam.page = this.pageInfo

      this
        .$post(this.baseURL + this.api.query, tmpParam)
        .then(data => {
          this.rows = this.initCheckbox(data.rows)
          this.total = data.total

          // 强制刷新dom,防止checkbox出现问题
          this.$nextTick(() => {
            this.show = true
          })
        })
    },

    // 改变页码
    pageChange (val) {
      const num = val - this.pageInfo.page
      if (typeof (this.pageInfo.page) === 'string') {
        this.pageInfo.page = parseInt(this.pageInfo.page)
      }
      if (this.pageInfo.page + num > this.maxPage) {
        return
      }
      if (this.pageInfo.page + num <= 0) {
        return
      }
      this.pageInfo.page += num
      this.checkbox.checked = false
      this.getList()
    },

    // 初始化编辑表单
    initEditForm () {
      const tmpForm = {}
      for (let index = 0; index < this.fields.length; index++) {
        const field = this.fields[index]
        tmpForm[field.field] = ''
      }
      this.editForm = tmpForm
    },

    // 初始化查询表单
    initSearchForm () {
      const tmpForm = {}
      for (let index = 0; index < this.fields.length; index++) {
        const field = this.fields[index]
        tmpForm[field.field] = ''
      }
      this.form = tmpForm
    },

    // 按钮点击事件
    btnClick (btn) {
      if (typeof btn.click !== 'undefined') {
        btn.click(this.getSelectedRows(), this)
      }
    },

    keydownHandle (event) {
      var e = event || window.e
      var keyCode = e.keyCode || e.which
      switch (keyCode) {
        case 13:
          this.getList()
          break
      }
    },

    afterEnter () {
      const modal = this.$refs.modal
      const width = modal.offsetWidth
      const height = modal.offsetHeight
      // 如果不是是偶数,则加0.5px
      if (width % 2 !== 0) {
        this.transformX = 'calc(-50% + 0.5px)'
      } else {
        this.transformX = '-50%'
      }

      if (height % 2 !== 0) {
        this.transformY = 'calc(-50% + 0.5px)'
      } else {
        this.transformY = '-50%'
      }

      this.transform = 'translate(' + this.transformX + ',' + this.transformY + ')'
    },

    // 初始化query条件存在情况
    initQueryForm () {
      if (this.query != null) {
        for (const queryKey in this.query) {
          if (this.query.hasOwnProperty(queryKey)) {
            const queryItem = this.query[queryKey]
            // 遍历条件,满足则填充
            for (const formKey in this.form) {
              if (this.form.hasOwnProperty(formKey)) {
                if (queryKey === formKey) {
                  this.form[formKey] = queryItem
                }
              }
            }
          }
        }
      }
    }
  },

  created () {
    this.initEditForm()
    this.initSearchForm()
    this.getList()
    document.addEventListener('keydown', this.keydownHandle)
    // query条件初始化存在情况
    this.initQueryForm()
  },

  beforeDestroy () {
    document.removeEventListener('keydown', this.keydownHandle)
  },

  watch: {
    'pageInfo.rows': function (newVal, oldVal) {
      if (newVal <= 0) {
        this.pageInfo.rows = oldVal
      }
    },

    'pageInfo.page': function (newVal, oldVal) {
      if (newVal <= 0 && newVal > this.maxPage) {
        this.pageInfo.page = oldVal
      }
    }
  }

  // components: {
  //   Loading
  // }

}

</script>
<style lang="scss" scoped>
  .form .input {
    // margin-top: 8px;
    margin-right: 8px;
  }

  .form .button {
    margin-top: 8px;
    margin-right: 8px;
  }

  .pagination .rows {
    float: right;
  }

  .tool-bar {
    float: right;

    .button {
      margin-right: 5px;
    }
  }

  .el-date-editor.el-input,
  .el-date-editor.el-input__inner {
    width: 180px;
    // width: 100%;
  }

  .el-select {
    width: 180px;
    // width: 100%;
  }

  .el-form-item--mini.el-form-item,
  .el-form-item--small.el-form-item {
    margin-bottom: 16px;
  }

  .el-form-item__label {
    overflow: hidden !important;
    text-overflow: ellipsis !important;
    white-space: nowrap !important;
  }

  /deep/ :focus {
    outline: 0;
  }
</style>
